package com.teaphy.demo;

import com.teaphy.annotations.Author;
import com.teaphy.annotations.Explain;
import com.teaphy.annotations.NotNull;
import com.teaphy.data.Location;
import com.teaphy.data.Student;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.Arrays;

public class MethodDemo {
	
	public static void main(String[] args) {
		Class<Student> clz = Student.class;

		// 获取方法 testMethod
		try {
			Method methodTest = clz.getMethod("testMethod",
					String.class,
					Object.class,
					Object.class,
					int[].class);

			// 1. Annotation(注解)
			// 1.1 getAnnotation()-> 获取改Method的注解列表
			Annotation[] annotations = methodTest.getAnnotations();
			System.out.println("getAnnotations(): " + Arrays.toString(annotations));
			// 1.2 getAnnotation(Class) -> 判断该Method是否被指定的Annotation注解。
			// 如果是，返回该注解，否则，返回null.
			Explain annoExplain = methodTest.getAnnotation(Explain.class);
			if (null == annoExplain) {
				System.out.println("当前Method-testMethod没有被Explain注解：" + annoExplain);
			} else {
				System.out.println("当前Method-testMethod被Explain注解：" + annoExplain);
			}

			NotNull annoNotNull = methodTest.getAnnotation(NotNull.class);
			if (null == annoNotNull) {
				System.out.println("当前Method-testMethod没有被NotNull注解：" + annoNotNull );
			} else {
				System.out.println("当前Method-testMethod被NotNull注解：" + annoNotNull);
			}

			// 1.3 getDeclaredAnnotations() -> 返回此Method的直接注解
			Annotation[] declaredAnnotations = methodTest.getDeclaredAnnotations();
			System.out.println("getDeclaredAnnotations(): " + Arrays.toString(declaredAnnotations));

			// 2 Parameter
			// 2.1 getParameterCount() -> 返回参数个数
			int parameterCount = methodTest.getParameterCount();
			System.out.println("getParameterCount(): " + parameterCount);

			// 2.2 getParameterTypes() -> 返回一个Class<?>数组，表示参数类型
			Class<?>[] parameterTypes = methodTest.getParameterTypes();
			System.out.println("getParameterTypes(): " + Arrays.toString(parameterTypes));

			// 2.3 getTypeParameters() -> 返回TypeVariable数组，该数组的元素表示以
			// 声明顺序表示的泛型声明的类型变量。
			TypeVariable<Method>[] typeParameters = methodTest.getTypeParameters();
			System.out.println("getTypeParameters(): " + Arrays.toString(typeParameters));

			// 2.4 getGenericParameterTypes() -> 返回Type数组，该数组表示以声明顺序的
			// 形式参数类型。
			Type[] genericParameterTypes = methodTest.getGenericParameterTypes();
			System.out.println("getGenericParameterTypes(): " + Arrays.toString(genericParameterTypes));

			// 2.4 methodTest.getParameterAnnotations()-> 返回Annotation[][]，其中，
			// 子数组表示以声明顺序的形式参数的注解列表。
			Annotation[][] parameterAnnotations = methodTest.getParameterAnnotations();
			for (int i = 0; i < parameterAnnotations.length; i++) {
				System.out.println("methodTest.getParameterAnnotations() - " + i + ": " + Arrays.toString(parameterAnnotations[i]));
			}

			// 3. ReturnType
			// 3.1 getReturnType() -> Class<?> ：返回一个Class对象，表示此Method对象所表示的
			// 方法的返回类型
			Class<?> returnType = methodTest.getReturnType();
			System.out.println("getReturnType(): " + returnType);

			// 3.2 getGenericReturnType() -> Type：返回一个Type对象，该对象表示此Method对象所
			// 表示的方法的返回类型。
			Type genericReturnType = methodTest.getGenericReturnType();
			System.out.println("getGenericReturnType(): " + genericReturnType);

			// 4 DefaultValue
			// 4.1 getDefaultValue() -> Object: 返回由此Method实例表示的注解(Annotation)成员的默认值。
			// 1. 如果成员是原始类型，则返回相应的包装器类型的实例。
			// 2. 如果没有默认值，或者方法实例不表示注解类型的声明成员，则返回null
			// methodTest不是注解类型的成员，返回null
			Object defaultValue = methodTest.getDefaultValue();
			System.out.println("getDefaultValue(): " + defaultValue);
			Class<Author> clzAuthor = Author.class;
			// methodAuthors是注解Author的成员，而且其默认值为"teaphy"，故返回值为"teaphy"
			Method methodAuthors = clzAuthor.getMethod("authors");
			Object defaultAuthors = methodAuthors.getDefaultValue();
			System.out.println("Annotation.getDefaultValue()：" + defaultAuthors);
			// methodVersion是注解Author的成员，但其没有默认值，故返回值为null
			Method methodVersion = clzAuthor.getMethod("version");
			Object defaultVersion = methodVersion.getDefaultValue();
			System.out.println("Annotation.getDefaultValue()：" + defaultVersion);

			// 5. Modifier
			// getModifiers() -> int：返回此方法的修饰符
			int modifier = methodTest.getModifiers();
			String mod = Modifier.toString(modifier);
			System.out.println("Modifier: " + mod);

			// 6 Exception
			// 6.1 getExceptionTypes() -> Class<?>[]：返回Class数组，这些对象表示其在执行时抛出的
			// 异常类型，只包括在方法声明时抛出的异常，不包括方法体中抛出的异常。
			Class<?>[] exceptionTypes = methodTest.getExceptionTypes();
			System.out.println("getExceptionTypes(): " + Arrays.toString(exceptionTypes));
			// getGenericExceptionTypes() -> Type[]：返回Type数组，这些对象表示其在执行时抛出的
			// 异常类型。，只包括在方法声明时抛出的异常，不包括方法体中抛出的异常。
			Type[] genericExceptionTypes = methodTest.getGenericExceptionTypes();
			System.out.println("getGenericExceptionTypes(): " + Arrays.toString(genericExceptionTypes));

			// 7 invoke
			Student student = new Student<String>("tesst");
			Location location = new Location("山东", "青岛", "崂山");
			methodTest.invoke(student, "testAA",
					location,
					"VVVV",
					new int[]{6, 7, 8});
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
			System.out.println("找不到指定方法-testMethod");
		} catch (IllegalAccessException | InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}
